///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
#ifndef __CGPROGRAM_H__
#define __CGPROGRAM_H__

#include <Config.h>
#include <Shader/GPUProgram.h>
#include <string>
#include <map>
#include <vector>

//-----------------------------------------------------------------------------

typedef	struct _struct_shader_var_cg_
{
	u8		func;
	CGparameter	param;
	union
	{
		GLfloat	vFloat[4];
		GLint	vInt[4];
	}	value;

	_struct_shader_var_cg_(u8 f, CGparameter p, GLfloat v)
	{
		func = f;
		param = p;
		value.vFloat[0] = v;
	}

	_struct_shader_var_cg_(u8 f, CGparameter p, GLfloat *v, u8 size)
	{
		func = f;
		param = p;
		memcpy( value.vFloat, v, sizeof( GLfloat ) * size );
	}

	_struct_shader_var_cg_(u8 f, CGparameter p, GLint v)
	{
		func = f;
		param = p;
		value.vInt[0] = v;
	}

	_struct_shader_var_cg_(u8 f, CGparameter p, GLint *v, u8 size)
	{
		func = f;
		param = p;
		memcpy( value.vInt, v, sizeof( GLint ) * size );
	}

}	_shader_var_cg_;

/**
* Implementeaza folosind Cg GPUProgram
*/
class CgProgram : public GPUProgram
{
private:
	/**
	* Context Cg; poate contine mai multe shadere vertex/fragment
	*/
	CGcontext m_cgContext;
	
	/**
	* Vertex shader(program)
	*/
	CGprogram m_cgVertexShader;
	
	/**
	* Fragment shader(program)
	*/
	CGprogram m_cgFragmentShader;
	
	/**
	* Obiectul program ce contine atat fragment shaderul cat si vertex shaderul
	*/
	CGprogram m_cgCombinedShader;

	/**
	* Profil Cg, folosit pentru crearea vertex shader pe GPU
	*/
	CGprofile m_cgVertexProfile;

	/**
	* Profil Cg, folosit pentru crearea fragment shader pe GPU
	*/
	CGprofile m_cgFragmentProfile;
	
	/**
	* Map pentru pastrarea parametrilor programului Cg
	*/
	std::map<std::string, CGparameter> m_cgParametersMap;

	/**
	*	Shader vars saves
	*/
	std::vector<_shader_var_cg_> m_cgShaderVarSaves;

	void		processSavedVars();

public:
	/**
	* Constructor fara parametri; se poate incarca un program cu Load()
	*/
	CgProgram();
	
	/**
	* Constructor ce creeaza si incarca un program Cg
	* dat prin vertex si/sau fragment shader
	*/
	CgProgram(File* sourceVS, File* sourceFS, const char *vertexFunc, const char *fragFunc);
	
	/**
	* Incarca parametrii programului Cg si ii pune in map-ul m_cgParametersMap
	*/
	virtual void LoadParameters();
	
	/**
	*	Has parameter
	*/
	bool HasParameter(const char* paramName);

	/**
	* Obtinem pointerul la un parametrul dat
	*/
	CGparameter GetParameter(const char* paramName);

	// Mostenite din GPUProgram
	bool Load(File* sourceVS, File* sourceFS, const char *vertexFunc = "", const char *fragFunc = "", const char *argsV = "", const char *argsF = "");

	bool Compile();

	bool Link();

	bool Validate();

	virtual void SetParameter1i(const char* paramName, int value);
	virtual void SetParameter2i(const char* paramName, int* value);
	virtual void SetParameter3i(const char* paramName, int* value);
	virtual void SetParameter4i(const char* paramName, int* value);

	virtual void SetParameter1f(const char* paramName, float value);
	virtual void SetParameter2f(const char* paramName, float* value);
	virtual void SetParameter3f(const char* paramName, float* value);
	virtual void SetParameter4f(const char* paramName, float* value);

	virtual void SetParameterTexture(const char* paramName, GLuint textureHandle, GLuint textureUnit);
	virtual void EnableParameterTexture(const char* paramName);

	virtual void SetParameterStateMatrix(const char* paramName, CGGLenum stateMatrixType, CGGLenum transform);
	virtual void SetParameterMatrixf(const char* paramName, GLfloat *mat);

	void Use(bool use = true);

	void Delete();

	virtual ~CgProgram();
};

#endif	//	__CGPROGRAM_H__
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
